//
//  renderer.m
//  V3d_Cocoa
//
//  Created by Y my on 11-4-23.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Renderer.h"

@interface Renderer ()

- (void)setToDefault;

@end


@implementation Renderer
@synthesize pixelPerEdge;
@synthesize levelLowBound, levelUpBound;
@synthesize viewImage;

- (id)initWithViewWidth:(unsigned short)width
				 Height:(unsigned short)height
		BackgroundColor:(RGB)color
{
	self = [super init];
	if (self)
	{
		[self setToDefault];
		
		viewWidth = width;
		viewHeight = height;
		backgroundColor = color;
	}
	return self;
}

- (void)dealloc
{
	if (viewImage)
	{
		free(viewImage);
	}
	
	if (matMoveToOri)
	{
		[matMoveToOri release];
	}
	
	if (matScale)
	{
		[matScale release];
	}
	
	if (matRotate)
	{
		[matRotate release];
	}
	
	if (matMoveBack)
	{
		[matMoveBack release];
	}
	[super dealloc];
}

// transform ///////////////////////

//（X, Y）: 旋转轴上一点（另一点为原点，旋转轴始终位于xoy平面中），Angle：旋转角度（弧度，逆时针）
- (void)rotateX:(float)x Y:(float)y Angle:(float)angle
{
	if (x == 0 && y == 0)
	{
		return;
	}
	
	if (angle == 0)
	{
		return;
	}
	
	Matrix4* matRotateZ = [[Matrix4 alloc] init];		// 绕Z轴转，使得原旋转轴与Y轴重合
	Matrix4* matRotateBackZ = [[Matrix4 alloc] init];	// 绕Z轴转回
	Matrix4* matRotateAngle = [[Matrix4 alloc] init];	// 绕现在的旋转轴，即Y轴，旋转angle

	float len;	// (x, y)与(0, 0)之间的距离

	float cosZ;	// 绕Z轴旋转的角度的cos值
	float sinZ;	// 绕Z轴旋转的角度的sin值
	float cosA;	// 绕Y轴旋转的角度的cos值
	float sinA;	// 绕Y轴旋转的角度的sin值
	
	len = sqrt(x * x + y * y);
	cosZ = y / len;
	sinZ = x / len;
	cosA = cosf(angle);
	sinA = sinf(angle);

	// 绕Z轴转，使得原旋转轴与Y轴重合
	matRotateZ._00 = cosZ;		matRotateZ._01 = sinZ;
	matRotateZ._10 = -sinZ;		matRotateZ._11 = cosZ;
	
	// 绕Z轴转回
	matRotateBackZ._00 = cosZ;		matRotateBackZ._01 = -sinZ;
	matRotateBackZ._10 = sinZ;		matRotateBackZ._11 = cosZ;
	
	// 绕现在的旋转轴，即Y轴，旋转angle
	matRotateAngle._00 = cosA;	matRotateAngle._02 = -sinA;
	matRotateAngle._20 = sinA;	matRotateAngle._22= cosA;
	
	[matRotate multiple:matRotateZ];
	[matRotate multiple:matRotateAngle];
	[matRotate multiple:matRotateBackZ];
	
	[matRotateZ release];
	[matRotateAngle release];
	[matRotateBackZ release];
	
	hasRotated = YES;
	
}

// （X, Y）：平移向量
- (void)translateX:(float)x Y:(float)y
{
	if (x == 0 && y == 0)
	{
		return;
	}
	moveX += (short)x;
	moveY += (short)y;
	
	hasMoved = YES;
}

- (void)reset
{
	[matRotate clear];
	moveX = 50;
	moveY = 10;
	pixelPerEdge = 2;
	hasRotated = YES;
	hasMoved = YES;
}

// setup /////////////////////////////////

- (void)setViewWidth:(unsigned short)width
			  Height:(unsigned short)height
	 BackgroundColor:(RGB)color
{
	viewWidth = width;
	viewHeight = height;
	backgroundColor = color;
	hasMoved = YES;
}

- (void)setVolData:(id <VolDataDelegate>)vData;
{
	rawData = vData.rawData;
	volData = vData;
	channelCount = vData.channelCount;
	matMoveToOri._30 = -vData.x_len / 2;
	matMoveToOri._31 = -vData.y_len / 2;
	matMoveToOri._32 = -vData.z_len / 2;
	matMoveBack._30 = vData.x_len / 2;
	matMoveBack._31 = vData.y_len / 2;
	matMoveBack._32 = vData.z_len / 2;
}

// main function ////////////////////////////

- (CGImageRef)proceed
{
	// 由子类实现
	return NULL;
}

- (void)calImageSize
{
	Point3D* point[8];
	for (char i = 0; i < 8; i++)
	{
		point[i] = [[Point3D alloc] init];
	}
	point[1].x = volData.x_len;
	point[2].y = volData.y_len;
	point[3].x = volData.x_len; point[3].y = volData.y_len;
	point[4].z = volData.z_len;
	point[5].x = volData.x_len; point[5].z = volData.z_len;
	point[6].y = volData.y_len; point[6].z = volData.z_len;
	point[7].x = volData.x_len; point[7].y = volData.y_len; point[7].z = volData.z_len;
	
	matScale._00 = matScale._11 = matScale._22 = (float)pixelPerEdge / 2.0;
	matMoveBack._30 *= matScale._00;
	matMoveBack._31 *= matScale._00;
	
	matFinalProj = [[Matrix4 alloc] init];
	[matFinalProj multiple:matMoveToOri];
	[matFinalProj multiple:matRotate];
	[matFinalProj multiple:matScale];
	[matFinalProj multiple:matMoveBack];
	
	for (char i = 0; i < 8; i++)
	{
		[point[i] multiple:matFinalProj];
	}
	
	short imageRight, imageBottom;
	
	imageLeft = imageTop = 0x7fff;
	imageRight = imageBottom = 0xffff;
	
	for (char i = 0; i < 8; i++)
	{
		if (imageLeft > point[i].x)
		{
			imageLeft = floor(point[i].x);
		}
		if (imageRight < point[i].x)
		{
			imageRight = ceil(point[i].x);
		}
		if (imageTop > point[i].y)
		{
			imageTop = floor(point[i].y);
		}
		if (imageBottom < point[i].y)
		{
			imageBottom = ceil(point[i].y);
		}
	}
	
	if (entireImage)
	{
		free(entireImage);
	}
	imageWidth = imageRight - imageLeft + 1;
	imageHeight = imageBottom - imageTop + 1;
	entireImage = (RGB*) malloc(sizeof(RGB) * imageWidth * imageHeight);
	memset(entireImage, 0, sizeof(RGB) * imageWidth * imageHeight);
}

- (void)clip
{
	short imageX, imageY;
	short viewX, viewY;
	for (imageY = 0; imageY < imageHeight; imageY++)
	{
		viewY = imageY + moveY;
		if (viewY < 0 || viewY >= viewHeight)
		{
			continue;
		}
		
		for (imageX = 0; imageX < imageWidth; imageX++)
		{
			viewX = imageX + moveX;
			if (viewX < 0 || viewX >= viewWidth)
			{
				continue;
			}
			viewImage[viewY * viewWidth + viewX] = entireImage[imageY * imageWidth + imageX];
		}
	}
}

// private /////////////////////////////////
- (void)setToDefault
{
	pixelPerEdge = 2;
	viewWidth = viewHeight = 0;
	SET_COLOR(backgroundColor, 0, 0, 0);
	levelLowBound = 10;
	levelUpBound = 255;
	hasRotated = YES;
	hasMoved = YES;
	
	viewImage = NULL;
	matMoveToOri = [[Matrix4 alloc] init];
	matScale = [[Matrix4 alloc] init];
	matRotate = [[Matrix4 alloc] init];
	matMoveBack = [[Matrix4 alloc] init];
	moveX = 50;
	moveY = 10;
}
@end
